trait Term 
  case class Name(name: String) extends Term
  case class LocalVal(name: String, tpe: Option[Type], value :Term, scope: Term) extends Term 

trait Type
  case class Inst (e: Term) extends Type

  trait CoreComponent
  
trait ExtendedComponent requires (CoreComponent with ExtendedComponent)
object o{val f=new CoreComponent with ExtendedComponent}

class Map {
  def term(e: Term): Term = e match {
    case LocalVal(n, t, v, s) => 
      LocalVal(n, option(t)(typ), term(v), term(s))
    case _ => e
  }
  def typ(t: Type): Type = t match {
    case Inst(e) => Inst(term(e))
  }  
  def option[t,s](o: Option[t])(f: t=>s): Option[s] 
    = o match {
    case Some(obj) => Some(f(obj))
    case None      => None
  }  
  def terms(ts: List[Term]): List[Term] = {
    for(val t <- ts) yield term(t)
  }
}


trait ECore {        
  [open] trait Expr[t]
    case class Num(n :Int) extends Expr[Int]
}

trait EEval requires (ECore with EEval) {
  trait Expr[t] {
          def eval :t 
  }
  
  case class Num(n :Int) extends Expr[Int]{
          def eval = n
  }
}

[close] class Deployment extends ECore with EEval 

class Subst(name: String, to: Term) extends Map {
  override def term(e: Term): Term = e match {  
    case Name(n) if (name == n) => to
  
    // avoid capture
    case LocalVal(n, t, v, scope) if (name != n 
            && (to match { case Name(n2) => n == n2 
                           case _ => false})) => 
      val newN = freshName // defined elsewhere
      val newScope = (new Subst(n, Name(newN))) term scope
      term(LocalVal(newN, t, v, newScope))

    // name is bound in scope, don't substitute there
    case LocalVal(n, t, v, scope) if (name == n) => 
      LocalVal(n, option(t)(typ), term(v), scope)

    case _ => super.term(e)
  }
  
  def freshName: String = "foo"
}


trait Traverser  {
    type CCT[cc, cts] = cc[cts]
                           for(val ct <- cts) yield ResultT[ct]
    type ResultT[T] = T /* match {
      case cc[cts*]: CaseClass => CCT[cc, cts]
      case _ => T
    }*/

    def traverse[T](obj: T): ResultT[T] = obj match {
      case cc((args: ats)*) => 
        new CCT[cc, cts]( for(val Pair(arg, argT) <- args.zipWith(ats)) yield traverse[argT](arg) )
      case _ => obj
    } 
  }